/**
 * Node.java
 * 
 * 	A graph node ADT that contains an element of any type T, 
 *  color (MAGENTA or CYAN), and list of adjacent nodes. 
 *  The adjacency list is implemented with a HashSet to 
 *  give a constant asymptotic runtime O(1) for adding or
 *  retrieving elements.
 * 
 *  @param <T> the Node's element (associated value).
 *  
 *  @author Emma Strubell
 *  @author Avner Maiberg
 *  COS350 - Latour
 *  April 15, 2010
 */

package com.mercator.client.graph;

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;

public abstract class Node<T extends Comparable<? super T>, A extends Node<T,A>> implements Comparable<A> , Iterable<A>
{
    // The data in the node
    protected T element; 
    // whether this node is the pivot node in a graph (default: no)
    protected boolean isPivot = false;
   
 //   public static final GColor CYAN = GColor.CYAN;
 //   public static final GColor MAGENTA = GColor.MAGENTA;

    // the color of the node
   // public GColor gcolor;
    
    // set of nodes adjacent to the current node
    public HashSet<A> adjacentNodes;
    
    /**
     * Constructor.
     * 
     * Creates a new Node with given element elem and initializes the color
     * to MAGENTA.
     * 
     * @param elem The element.
     */
    public Node(T elem) {
	this.element = elem;
	//this.gcolor = CYAN;
	
	this.adjacentNodes = new HashSet<A>();
    }
    
    public Node(T elem, boolean pivot) {
	this(elem);
	this.isPivot = pivot;
    }

    /**
     * Returns true if the current node is equal to given Node n.
     * 
     * @param n the Node with which to compare
     * @return boolean whether the value associated with this node is equal to
     * the value of the given Node
     */
    public boolean equals(A n) {
	return this.element.equals(n.element);
    }

    @Override
    public int hashCode() {
	return element.hashCode();
    }

    @Override
    public String toString() {
    	if(!this.adjacentNodes.isEmpty()){
    	String s = this.element + ": [";
    	for(A u : this)
    		s+=u.element +", ";
    	return s.substring(0, s.length()-2) + "]";
    	}
    	return this.element.toString();
    }

    /**
     * @param c the color of this node (MAGENTA or CYAN)
     */

    /**
     * Connects the given Node to this node by adding it to this Node's
     * adjacency list.
     * 
     * @param n the Node to connect to this
     */
    public void connect(A n) {
   	if((!adjacentNodes.contains(n) && !n.adjacentNodes.contains(getThis()))){
    		adjacentNodes.add(n);
    		n.adjacentNodes.add(getThis());
    	}
    }
    public void connectAll(A node){
    	adjacentNodes.addAll(node.adjacentNodes);
    }
    
    public void connectAll(Collection<A> col){
    	adjacentNodes.addAll(col);
    }
    
    public void disconnect(A n){
	adjacentNodes.remove(n);
    }

    /**
     * @return the value of type T associated with this node
     */
    public T getElement() {
    	return element;
    }
    
    public boolean isAdjacent(A n)
    {
	return adjacentNodes.contains(n);
    }

    /**
     * @return whether this Node is greater than, less than, or equal to the
     * given Node based on the natural ordering of their contained values
     */
    public int compareTo(A o) {
    	return this.element.compareTo(o.element);
    }
    
    protected abstract A getThis();
    
    public Iterator<A> iterator(){
    	return adjacentNodes.iterator();
    }
    
    
    
    public int getDegree(){
    	return adjacentNodes.size();
    }
        
    public boolean isPivot(){ return this.isPivot; }

	public abstract int hashcode();
	
	public boolean contains(A node){
		return this.adjacentNodes.contains(node);
	}
	
	public boolean containsAll(A node){
		return this.adjacentNodes.containsAll(node.adjacentNodes);
	}
	
	
}
